/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package practica1compi1;

import java.util.*;
import java.io.*;
import java.util.ArrayList.*; 
import java.lang.String;
/**
 *
 * @author Otto
 */
public class Thompson {
    List<clsToken> _Listado = new ArrayList<clsToken>();
    String matrizOriginal[][];// = new String[1][1];
    List<clsToken> _Alfabeto = new ArrayList<clsToken>();
    int sizeTransition =0; 
    int UltimoEstado=0;
     List<clsToken> Listado;
     
    static final int Total=50; 
    public void SetAlfabeto(List<clsToken> Listado){
        sizeTransition=Listado.size();
        _Alfabeto = Listado;
        matrizOriginal  = new String[sizeTransition+2][Total];
        
        matrizOriginal[0][0]="ESTADO"; 
        for (int i=0;i<sizeTransition;i++)        {
            matrizOriginal[i+1][0]=_Alfabeto.get(i)._value;
        }
         matrizOriginal[sizeTransition+1][0]="ε"; 
         
         sizeTransition++;
    }
    
    
    public boolean Analizar( List<clsToken> pListado){
        boolean lBolResult = false;
        Listado=pListado;
 
        
       calcular(Listado.get(0),0,pListado);
        
        return lBolResult;
    }
            /**
             * Metodo recursivo para crear la tabla  de  transiciones
             * @param TokenActual
             * @param posicionActual
             * @param pListado
             * @return 
             */ 
    private int calcular (clsToken TokenActual,int posicionActual,List<clsToken> pListado)    {
   //     int r1=posicionActual;
        int posRetro=0;
        switch(TokenActual._Tipo)        {
           case  5: // '*'
                 int Inicio=UltimoEstado;
                 posRetro=AgregarEpsilonAdelante(); 
                 posicionActual++;                 
                 posicionActual=calcular(pListado.get(posicionActual),posicionActual,pListado);
                 AgregarEpsilonAtras(UltimoEstado,posRetro);
                 AgregarEpsilonAdelante();
                 AgregarEpsilonAtras(Inicio,UltimoEstado);
               break;
           case 6:  // '.'
                 posicionActual++;
                 posicionActual=calcular(pListado.get(posicionActual),posicionActual,pListado);
                 posicionActual++;
                 posicionActual=calcular(pListado.get(posicionActual),posicionActual,pListado); 
                break;
            case 7:  // '?'
                 int Inicio2=UltimoEstado;
                 posRetro=AgregarEpsilonAdelante(); 
                 posicionActual++;                 
                 posicionActual=calcular(pListado.get(posicionActual),posicionActual,pListado);
                 //AgregarEpsilonAtras(UltimoEstado,posRetro);
                 AgregarEpsilonAdelante();
                 AgregarEpsilonAtras(Inicio2,UltimoEstado);
                break;
            case 8:  // '|'
                int posIni =UltimoEstado;
                AgregarEpsilonAdelante();
                posicionActual++;                 
                posicionActual=calcular(pListado.get(posicionActual),posicionActual,pListado);
             //   int posFin=AgregarEpsilonAdelante(UltimoEstado);
                int posFin=UltimoEstado;
                AgregarEpsilonAdelante(posIni);
                posicionActual++;                 
                posicionActual=calcular(pListado.get(posicionActual),posicionActual,pListado);
                 AgregarEpsilonAdelante(UltimoEstado);
                AgregarEpsilonAtras(posFin,UltimoEstado);
                break;
            case  9:  // '+'
                 posRetro=AgregarEpsilonAdelante(); 
                 posicionActual++;                 
                 posicionActual=calcular(pListado.get(posicionActual),posicionActual,pListado);
                 AgregarEpsilonAtras(UltimoEstado,posRetro);
                 AgregarEpsilonAdelante(); 
                break;
            case 10:  // ID
                 AgregarID(TokenActual); 
                 break;
        } 
        return posicionActual;
    }
    /**
     * Agrega un transicion desde un estado inicial hasta el estado final
     * @param estadoInicial
     * @return 
     */
   private int AgregarEpsilonAdelante(int estadoInicial)  {
       int pos=UltimoEstado;
       for (int i=1;i<=sizeTransition;i++){
            if ( matrizOriginal[i][0].equals("ε"))
            {
                for (int j=0;j<  Total;j++){
                    if (matrizOriginal[0][j].equals(String.valueOf(estadoInicial))){
                        UltimoEstado++;
                        if (matrizOriginal[i][j]==null)
                             matrizOriginal[i][j]= String.valueOf(UltimoEstado)+",";
                        else
                            matrizOriginal[i][j]=matrizOriginal[i][j]+String.valueOf(UltimoEstado)+",";
                         break;
                    }
                }  
                 matrizOriginal[0][pos+2]=String.valueOf(UltimoEstado);
                break;
            }
        }
       return UltimoEstado;
   }
   /**
    * Agrega una transcicion con ε desde un estado hasta otro estado
    * @param estadoInicial
    * @param estadoFinal
    * @return 
    */
    private int AgregarEpsilonAtras(int estadoInicial,int estadoFinal){
        for (int i=1;i<=sizeTransition;i++){
            if ( matrizOriginal[i][0].equals("ε"))
            {
                for (int j=0;j<Total;j++){
                    if (matrizOriginal[0][j].equals(String.valueOf(estadoInicial))){
                        if (matrizOriginal[i][j]==null)
                             matrizOriginal[i][j]= String.valueOf(estadoFinal)+",";
                        else
                            matrizOriginal[i][j]=matrizOriginal[i][j]+String.valueOf(estadoFinal)+",";
                         break;
                    }
                }        
                break;
            }
        }
        return UltimoEstado;
    }
    /**
     * Agrega una transicion con ε creando un nuevo estado
     * @return 
     */
    private int AgregarEpsilonAdelante()  {
         int pos=UltimoEstado; 
         for (int i=1;i<=sizeTransition;i++){
            if ( matrizOriginal[i][0].equals("ε"))
            { 
                matrizOriginal[0][pos+1] = String.valueOf(UltimoEstado);
            
                UltimoEstado++;
                if (matrizOriginal[i][pos+1]==null)
                    matrizOriginal[i][pos+1]= String.valueOf(UltimoEstado)+",";    
                else
                    matrizOriginal[i][pos+1]= matrizOriginal[i][pos+1]+String.valueOf(UltimoEstado)+",";  
                
                matrizOriginal[0][pos+2]=String.valueOf(UltimoEstado);
                break;
            }
        }
        return UltimoEstado;
    }
    /**
     * Funcion que agrega un estado con el valor que se envia en el token
     * @param Token
     * @return 
     */
    private int AgregarID(clsToken Token){
        
        int pos=UltimoEstado;
        for (int i=1;i<=sizeTransition;i++){
            if ( matrizOriginal[i][0].equals(Token._value))
            {
                //buscar si existe el estado si no crearlo 
                    matrizOriginal[0][pos+1] = String.valueOf(UltimoEstado);
 
                UltimoEstado++;
                if (matrizOriginal[i][pos+1] ==null)
                    matrizOriginal[i][pos+1] = String.valueOf(UltimoEstado)+",";
                else
                  matrizOriginal[i][pos+1] = matrizOriginal[i][pos+1] +String.valueOf(UltimoEstado)+",";
              
                matrizOriginal[0][pos+2]=String.valueOf(UltimoEstado);
                break;
            }
            
        }
       
        
        return UltimoEstado;
    }

   /**
    * Funcion para dibujar la matriz que esta en memoria que representa la tabla
    * de transiciones con ε del metodod de thompson
    */
    public void DibujarMatriz() {
//            System.out.println(sizeTransition);
//                System.out.println(UltimoEstado);
         for (int i=0;i<=UltimoEstado+1;i++)        {
             String strLinea = "";
             for (int j=0;j<=sizeTransition;j++){
                 strLinea= strLinea+matrizOriginal[j][i]+"\t";
             }
             System.out.println(strLinea);
        }
    }
    
    
    
    
    /*public void EscribirAFN(String strT){
        
        try{
            FileWriter fw = new FileWriter("C:\\Users\\Public\\Documents\\afn.txt",false);
            PrintWriter pw =new PrintWriter(fw);
                
                pw.println(strT);
                pw.close();
            
        } catch(Exception e){
            
        }
        
    }*/
    
    
    public void LlenarTxtAFN(){
        
        
        
        try{
            FileWriter fw = new FileWriter("C:\\Users\\Public\\Documents\\afn.txt",false);
            PrintWriter pw =new PrintWriter(fw);
                
                
          
        String strNuevaLinea="";
        
        //String strArchivo ="digraph AFN { \n ";
        pw.println("digraph AFN { \n ");
        pw.println("node [shape = circle];");
        pw.println("rankdir=LR;");
        
        for (int i=0;i<=UltimoEstado+1;i++){
             
            //String strLinea = "";
             
             for (int j=0;j<=sizeTransition;j++){
                 
                 //strLinea= strLinea+matrizOriginal[j][i]+"\t";
                 if (i==0){
                     break;
                 }
                 else{
                     
                     if (j==0){
                     strNuevaLinea="S"+ matrizOriginal[j][i] +" -> ";
                     }
                     
                     else if(matrizOriginal[j][i]!=null){
                         
                         //System.out.println(strEstados+"Para split");
                         
                         String strEstados=matrizOriginal[j][i];
                         String[] arrayEstados = strEstados.split(",");
                         
                         
                         for (int k = 0; k < arrayEstados.length; k++) {
                                //System.out.println(arrayEstados[k]);
                                if(k<arrayEstados.length){
                                    //strArchivo=strArchivo+strNuevaLinea+"S"+arrayEstados[k]+"[ label = \""+matrizOriginal[j][0]+"\" ];\n";
                                    pw.println(strNuevaLinea+"S"+arrayEstados[k]+"[ label = \""+matrizOriginal[j][0]+"\" ];\n");
                                }
                                else{
                                    //strArchivo=strArchivo+strNuevaLinea+"S"+arrayEstados[k]+"[ label = \""+matrizOriginal[j][0]+"\" ];";
                                    pw.println(strNuevaLinea+"S"+arrayEstados[k]+"[ label = \""+matrizOriginal[j][0]+"\" ];");
                                }
                                
                         }
                         
                         
                      }
                 }
             }
             
             
        }
        
        //System.out.println(strArchivo);
        pw.println("}");
        pw.close();
        
        } catch(Exception e){
            
        }
        
    }
    
    public String[][] GetMatriz(){
        return matrizOriginal;
    }
    
}
